package com.unlcn.ils.crsc.service.crsc.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.unlcn.ils.crsc.dao.mapper.crsc.CrscOtdMapper;
import com.unlcn.ils.crsc.dao.model.crsc.CrscOtd;
import com.unlcn.ils.crsc.dao.model.crsc.CrscOtdLog;
import com.unlcn.ils.crsc.service.crsc.CrscOTDLogService;
import com.unlcn.ils.crsc.service.crsc.CrscOTDService;
import com.unlcn.ils.crsc.service.ftp.util.FtpUtil;
import com.unlcn.ils.crsc.service.util.BaseException;
import com.unlcn.ils.crsc.service.xml.util.XmlUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class CrscOTDServiceImpl implements CrscOTDService{

    private static final Logger logger = LoggerFactory.getLogger(CrscOTDServiceImpl.class);

    @Value("${ftp.sourcePath}")
    private String sourcePath;

    @Value("${ftp.relativeLocalPath}")
    private String relativeLocalPath;

    @Value("${ftp.backupPath}")
    private String backupPath;

    @Value("${ftp.isdeleteFile}")
    private Boolean isdeleteFile;

    private final String xpath = "//table/rows/row";

    @Autowired
    private CrscOtdMapper crscOtdMapper;

    @Autowired
    private CrscOTDLogService crscOTDLogService;

    private int intCount;

    /**
     *
     * @param sourcePath 源目录
     * @param localpath 目的目录
     * @return
     * @throws BaseException
     */
    private List<String> getFTPFiles(String filterName,String sourcePath,String localpath) throws BaseException{

        List<String> listFTPFileNames = Lists.newArrayList();

        try{
            listFTPFileNames = FtpUtil.listFiles(sourcePath,filterName);
            //下载
            listFTPFileNames.forEach(filename -> FtpUtil.downloadFile(filename,localpath));

            if(CollectionUtils.isEmpty(listFTPFileNames)){
                if (localpath.startsWith("/") && localpath.endsWith("/")) {
                    File diretory = new File(localpath);
                    if(diretory.isDirectory()){
                        List<String> fileNames = Arrays.asList(diretory.list()).stream().filter(filter -> filter.toLowerCase().endsWith(".xml")).collect(Collectors.toList());
                        listFTPFileNames.addAll(fileNames);
                    }
                }
            }
        }
        catch (Exception e){
            logger.error(e.getMessage());
            throw new BaseException(e.getMessage());
        }

        return  listFTPFileNames;
    }


    /**
     * 读取文件
     * @param filepath
     */
    public List<CrscOtd> readFile(String filename,String filepath,String backupPath){
        List<CrscOtd> crscOtdList = Lists.newArrayList();

        try {
            File filesource = new File(filepath + filename);
            if(filesource.isFile()){
                Document document = XmlUtil.parse(filepath + filename);
                List<Node> list = document.selectNodes(xpath);
                list.forEach(node -> {
                    if (node.getNodeType() == 1) {
                        Element element = (Element) node;
                        CrscOtd crscOtd = getCracOtd(filename,element);
                        EntityWrapper<CrscOtd> ew = new EntityWrapper<>();
                        ew.where("source_file = {0}",filename).and("vin = {0}",crscOtd.getVin());
                        int intCount = crscOtdMapper.selectCount(ew);
                        if(intCount <= 0){
                            crscOtdList.add(crscOtd);
                        }
                    }
                });

                //移动文件
                File filebackup = new File(backupPath + filename);
                if(!filebackup.exists()){
                    if (filesource.renameTo(filebackup)) {
                        logger.info("文件移动成功！文件名:{} 目标路径：{}",filename,backupPath);
                    } else {
                        logger.info("文件移动失败！文件名：《{}》 起始路径：{}",filename,backupPath);
                        throw new BaseException("文件移动失败！文件名:" + filename + " 起始路径:" + filepath);
                    }
                }
            }
        } catch (DocumentException ex) {
            logger.error(ex.getMessage());
            throw new BaseException(ex.getMessage());
        }

        return  crscOtdList;
    }


    /**
     * 存入数据库
     * @param crscOtds
     */
    @Transactional
    public void saveDb(List<CrscOtd> crscOtds) throws BaseException{
        if(CollectionUtils.isEmpty(crscOtds)){
           return;
        }

        crscOtdMapper.insertBatch(crscOtds);
        intCount = crscOtds.size();
    }

    /**
     * 转化属性
     * @param element
     * @return
     * @throws BaseException
     */
    private CrscOtd getCracOtd(String filename,Element element) throws BaseException{

        CrscOtd crscOtd = new CrscOtd();
        crscOtd.setSourceFile(filename);

        DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd hh:mm");

        if(!Objects.isNull(element)){
            String rc = element.attributeValue("RC");
            if(!Strings.isNullOrEmpty(rc)){
                crscOtd.setRc(rc);
            }
            else{
                logger.error("文件："+ filename + "数据R/C为空");
                throw new BaseException("文件："+ filename + "数据R/C为空");
            }

            String fslsh = element.attributeValue("FSLSH");
            if(!Strings.isNullOrEmpty(fslsh)){
                crscOtd.setFslsh(fslsh);
            }
            else{
                logger.error("文件："+ filename + "发送流水号为空");
                throw new BaseException("文件："+ filename + "发送流水号为空");
            }

            String vin = element.attributeValue("VIN");
            if(!Strings.isNullOrEmpty(vin)){
                crscOtd.setVin(vin);
            }
            else{
                logger.error("文件："+ filename + "商品车唯一标识码为空");
                throw new BaseException("文件："+ filename + "商品车唯一标识码为空");
            }

            String ch = element.attributeValue("CH");
            if(!Strings.isNullOrEmpty(ch)){
                crscOtd.setCh(ch);
            }

            String hph = element.attributeValue("HPH");
            if(!Strings.isNullOrEmpty(hph)){
                crscOtd.setHph(hph);
            }

            String zprq = element.attributeValue("ZPRQ");
            if(!Strings.isNullOrEmpty(zprq)){
                crscOtd.setZprq(zprq);
            }

            try{
                String xdsj = element.attributeValue("XDSJ");
                if(!Strings.isNullOrEmpty(xdsj)){
                    crscOtd.setXdsj(format1.parse(xdsj));
                }

                String zcjssj = element.attributeValue("ZCJSSJ");
                if(!Strings.isNullOrEmpty(zcjssj)){
                    crscOtd.setZcjssj(format1.parse(zcjssj));
                }

                String fcsj = element.attributeValue("FCSJ");
                if(!Strings.isNullOrEmpty(fcsj)){
                    crscOtd.setFcsj(format1.parse(fcsj));
                }

                String xcjssj = element.attributeValue("XCJSSJ");
                if(!Strings.isNullOrEmpty(xcjssj)){
                    crscOtd.setXcjssj(format1.parse(xcjssj));
                }

                String psjssj = element.attributeValue("PSJSSJ");
                if(!Strings.isNullOrEmpty(psjssj)){
                    crscOtd.setPsjssj(format1.parse(psjssj));
                }

                String hdsj = element.attributeValue("HDSJ");
                if(!Strings.isNullOrEmpty(hdsj)){
                    crscOtd.setHdsj(format1.parse(hdsj));
                }

                String bgsj = element.attributeValue("BGSJ");
                if(!Strings.isNullOrEmpty(bgsj)){
                    crscOtd.setBgsj(format1.parse(bgsj));
                }

                String ts = element.attributeValue("TS");
                if(!Strings.isNullOrEmpty(ts)){
                    crscOtd.setTs(Integer.valueOf(ts));
                }

                String jd = element.attributeValue("JD");
                if(!Strings.isNullOrEmpty(jd)){
                    crscOtd.setJd(new BigDecimal(jd));
                }

                String wd = element.attributeValue("WD");
                if(!Strings.isNullOrEmpty(wd)){
                    crscOtd.setWd(new BigDecimal(wd));
                }
            }
            catch (ParseException ex){
                logger.error(ex.getMessage());
                throw new BaseException(ex.getMessage());
            }

            String jjdh = element.attributeValue("JJDH");
            if(!Strings.isNullOrEmpty(jjdh)){
                crscOtd.setJjdh(jjdh);
            }

            String thydqx = element.attributeValue("THYDQX");
            if(!Strings.isNullOrEmpty(thydqx)){
                crscOtd.setThydqx(thydqx);
            }


            String ysfs = element.attributeValue("YSFS");
            if(!Strings.isNullOrEmpty(ysfs)){
                crscOtd.setYsfs(ysfs);
            }

            String fwfs = element.attributeValue("FWFS");
            if(!Strings.isNullOrEmpty(fwfs)){
                crscOtd.setFwfs(fwfs);
            }

            String dcs = element.attributeValue("DCS");
            if(!Strings.isNullOrEmpty(dcs)){
                crscOtd.setDcs(dcs);
            }

            String fz = element.attributeValue("FZ");
            if(!Strings.isNullOrEmpty(fz)){
                crscOtd.setFz(fz);
            }

            String dz = element.attributeValue("DZ");
            if(!Strings.isNullOrEmpty(dz)){
                crscOtd.setDz(dz);
            }

            String pp = element.attributeValue("PP");
            if(!Strings.isNullOrEmpty(pp)){
                crscOtd.setPp(pp);
            }

            String wls = element.attributeValue("WLS");
            if(!Strings.isNullOrEmpty(wls)){
                crscOtd.setWls(wls);
            }

            String cx = element.attributeValue("CX");
            if(!Strings.isNullOrEmpty(cx)){
                crscOtd.setCx(cx);
            }

            String mdd = element.attributeValue("MDD");
            if(!Strings.isNullOrEmpty(mdd)){
                crscOtd.setMdd(mdd);
            }

            String ddh = element.attributeValue("DDH");
            if(!Strings.isNullOrEmpty(ddh)){
                crscOtd.setDdh(ddh);
            }

            String fcs = element.attributeValue("FCS");
            if(!Strings.isNullOrEmpty(fcs)){
                crscOtd.setFcs(fcs);
            }

            String bgz = element.attributeValue("BGZ");
            if(!Strings.isNullOrEmpty(bgz)){
                crscOtd.setBgz(bgz);
            }

            String sheng = element.attributeValue("SHENG");
            if(!Strings.isNullOrEmpty(sheng)){
                crscOtd.setSheng(sheng);
            }

            String shi = element.attributeValue("SHI");
            if(!Strings.isNullOrEmpty(shi)){
                crscOtd.setShi(shi);
            }

            String xian = element.attributeValue("XIAN");
            if(!Strings.isNullOrEmpty(xian)){
                crscOtd.setXian(xian);
            }
        }

        return crscOtd;
    }

    @Override
    public void readFTPFilesToSaveDB(Date date) throws BaseException{
        logger.info("开始读取文件");
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat formatter2 = new SimpleDateFormat("yyyyMMdd");
        String dateString = formatter.format(date);
        String filterName = formatter2.format(date);

        CrscOtdLog crscOtdLog = new CrscOtdLog();
        //文件方式
        crscOtdLog.setCallType("1");
        crscOtdLog.setCallUrl(sourcePath);
        //拉取文件
        crscOtdLog.setPullOrPush("0");
        crscOtdLog.setSystemQueryTime(date);
        crscOtdLog.setCallStartTime(new Date());
        crscOtdLog.setParameters(filterName);

        try{
            //创建目标文件夹
            String newRelativeLocalPath = relativeLocalPath + dateString + "/";
            File entryDir = new File(newRelativeLocalPath);
            //如果文件夹路径不存在，则创建文件夹
            if (!entryDir.exists() || !entryDir.isDirectory())
            {
                entryDir.mkdirs();
            }

            //创建备份文件夹
            String newBackupPath = backupPath + dateString + "/";
            entryDir = new File(newBackupPath);
            //如果文件夹路径不存在，则创建文件夹
            if (!entryDir.exists() || !entryDir.isDirectory())
            {
                entryDir.mkdirs();
            }

            //先下载文档
            List<String> ftpFileNames = this.getFTPFiles(filterName,sourcePath,newRelativeLocalPath);
            if(CollectionUtils.isEmpty(ftpFileNames)){
                crscOtdLog.setCallFileCount(0);
                crscOtdLog.setCallEndTime(new Date());
                crscOtdLog.setResultCount(0);
                crscOtdLog.setSuccess(true);
                crscOtdLog.setMessageCode("404");
                crscOtdLog.setMessage("文件不存在");
                crscOTDLogService.insert(crscOtdLog);
                return;
            }

            //存储状态
            crscOtdLog.setCallFileCount(ftpFileNames.size());
            String fileNameLists = ftpFileNames.stream().collect(Collectors.joining(","));
            crscOtdLog.setCallFiles(fileNameLists);
            crscOtdLog.setFilesCatalog(relativeLocalPath);

            ftpFileNames.forEach(filename -> {
                //读取文件
                List<CrscOtd> crscOtds = this.readFile(filename,newRelativeLocalPath,newBackupPath);
                if(CollectionUtils.isEmpty(crscOtds)){
                    logger.info("读取的文件中记录为空或者文件已经导入");
                    return;
                }

                //存入数据库
                this.saveDb(crscOtds);

                if(isdeleteFile){
                    logger.info("开始删除文件");
                    //删除FTP文件
                    try{
                        Boolean blnRtn = FtpUtil.DeleteFile(sourcePath,filename);
                        if(blnRtn){
                            logger.info("删除文件：" + filename + " 成功");
                        }
                    }
                    catch (IOException ex){
                        logger.error("删除文件：" + filename + " 失败");
                        throw new BaseException("删除文件：" + filename + " 失败");
                    }
                    logger.info("删除文件完成");
                }
            });

            crscOtdLog.setCallEndTime(new Date());
            crscOtdLog.setSuccess(true);
            crscOtdLog.setResultCount(intCount);
            crscOtdLog.setMessageCode("200");
            if(intCount ==0 ){
                crscOtdLog.setMessage("读取的文件中记录为空或者文件已经导入");
            }
            else{
                crscOtdLog.setMessage("读取成功");
            }

            crscOTDLogService.insert(crscOtdLog);

            //删除原有文件夹
            File sourceDir = new File(newRelativeLocalPath);

            if(sourceDir.isDirectory() && sourceDir.exists()){
                File[] files = sourceDir.listFiles();
                for (File file:files) {
                    file.delete();
                }
                boolean blnde = sourceDir.delete();
                if(blnde){
                    logger.info("删除文件夹完成");
                }
            }

            logger.info("读取文件完成");
        }
        catch (Exception ex){
            logger.error(ex.getMessage());
            crscOtdLog.setCallEndTime(new Date());
            crscOtdLog.setSuccess(false);
            crscOtdLog.setMessageCode("400");
            crscOtdLog.setMessage(ex.getMessage());
            crscOTDLogService.insert(crscOtdLog);
            throw new BaseException(ex.getMessage());
        }
    }

    @Override
    public List<CrscOtd> getOtdsByVin(String vinStrs) {
        List<CrscOtd> listOtds = Lists.newArrayList();
        List<String> vinList = Arrays.asList(vinStrs.split(","));
        if(!CollectionUtils.isEmpty(vinList)){
            listOtds =crscOtdMapper.selectOtdByVin(vinList);
        }
        return  listOtds;
    }

    @Override
    public List<CrscOtd> queryVinDetail(String vinStrs) {
        if (StringUtils.isEmpty(vinStrs)) {
            throw new BaseException("车架号信息不能为空");
        }
        List<CrscOtd> listOtds = Lists.newArrayList();
        List<String> vinList = Arrays.asList(vinStrs.split(","));
        if(!CollectionUtils.isEmpty(vinList)){
            listOtds =crscOtdMapper.selectOtdByVin(vinList);
        }
        return  listOtds;
    }
}
